//
// Created by martics on 24-9-5.
//
#include "container.h"
#include "namespace.h"
#include "tools.h"
#include <stdio.h>
#include <stdlib.h>
#define __USE_GNU
#include <sched.h>
#include <string.h>
#include <unistd.h>
#include <wait.h>
#include <errno.h>
#include <sys/mount.h>

#include "overlayfs.h"

#define HOSTNAME    "mtdocker"

char* merged = "rootfs/merged";

void setup_container() {
    printf("Setting up container environment...\n");

    if (0 != chdir(merged)) {
        const char* msg[strlen(merged) + 15];
        sprintf(msg, "chdir %s error!", merged);
        sys_err(msg);
        return;
    }
    if (0 != chroot(".")) {
        const char* msg[strlen(merged) + 20];
        sprintf(msg, "chroot %s error", merged);
        sys_err(msg);
        return;
    }

    if (-1 == mount("proc", "/proc", "proc", 0, NULL)) {
        sys_err("mount /proc error!");
        exit(EXIT_FAILURE);
    }
}

void run_container_process() {
    // 在子进程运行shell
    char* const args[] = {"/bin/bash", NULL};
    // 执行成功他会再回到/bin/bash
    execv("/bin/bash", args);

    perror("execv error");
    exit(EXIT_FAILURE);
}

int container_run() {
    const pid_t child_pid = fork();

    if (-1 == child_pid) {
        sys_err("fork error!");
        exit(EXIT_FAILURE);
    }

    if (0 == child_pid) { // 子进程
        printf("Parent (PID: %d) created a child (PID: %d)..\n", getppid(), getpid());
        {
            char* lowerdir = "rootfs/lowdir";
            char* upperdir = "rootfs/upperdir";
            char* workdir = "rootfs/workdir";
            char* procdir = "rootfs/lowdir/proc";

            ensure_directory_exists(lowerdir);
            ensure_directory_exists(upperdir);
            ensure_directory_exists(workdir);
            ensure_directory_exists(procdir);

            setup_overlayfs(lowerdir, upperdir, workdir, merged);
        }

        // 用户态的unshare最终会调用内核的sys_unshare
        if (-1 == unshare(CLONE_NEWUTS | CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC)) {
            sys_err("unshare error");
            exit(EXIT_FAILURE);
        }

        printf("enter container %d\n", getpid());

        {
            // 初始化容器
            set_container_hostname(HOSTNAME);
            setup_user_namespace(getpid());
        }

        {
            const pid_t pid = fork();
            if (pid < 0) {
                sys_err("Fork error!");
                exit(EXIT_FAILURE);
            }

            if (pid > 0) {
                waitpid(pid, NULL, 0);
                printf("container process (PID: %d) exit..\n", pid);
            } else {
                printf("enter container..\n");
                // 挂载mount
                setup_container();
                run_container_process();
            }
        }
    } else {
        waitpid(child_pid, NULL, 0);

        if (-1 == umount(merged)) {
            const char* msg[strlen(merged) + 20];
            sprintf(msg, "umount %s error!", merged);
            sys_err(msg);
        } else {
            printf("umount %s success..\n", merged);
        }
        printf("child (PID: %d) exit..\n", child_pid);
    }
    return EXIT_SUCCESS;
}